package com.learn.aop.proxy.jdk;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * https://www.cnblogs.com/mei0619/p/7094600.html
 * @date 2021/10/09 15:00
 **/
public class Test {

	public static void main(String[] args) {

		//目标对象
		UserService target = new UserService();

		/**
		 * 需要基于接口创建代理对象
		 * newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
		 */
		// 创建 UserInterface 接口的代理对象
		// 被封装的对象是 Object 类型，接受任意类型的对象
		Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(),
				target.getClass().getInterfaces(),
				new InvocationHandler() { //匿名内部类实现 JDK 的 InvocationHandler 接口
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						System.out.println("before...");
						Object result = method.invoke(target, args); // 通过反射机制调用某个类的方法
						System.out.println("after...");
						return result;
					}
				});

		/**
		 * 产生的代理对象的类型是 UserInterface，而不是 UserService
		 */
		UserInterface userService = (UserInterface) proxy;

		// 这里可以通过运行结果证明 proxy 是 Proxy 的一个实例，这个实例实现了 UserInterface 接口
		System.out.println(userService instanceof Proxy);

		// 这里可以看出 proxy 的 Class 类是 $Proxy0,这个 $Proxy0 类继承了 Proxy，实现了 UserInterface 接口
		System.out.println("userService的Class类是：" + userService.getClass().toString());

		System.out.print("userService中的属性有：");
		Field[] field = userService.getClass().getDeclaredFields();
		for(Field f:field){
			System.out.print(f.getName()+", ");
		}

		System.out.print("\n" + "userService中的方法有：");
		Method[] method = userService.getClass().getDeclaredMethods();
		for(Method m:method){
			System.out.print(m.getName()+", ");
		}

		System.out.println("\n" + "userService的父类是：" + userService.getClass().getSuperclass());

		System.out.print("userService实现的接口是：");
		Class<?>[] interfaces = userService.getClass().getInterfaces();
		for(Class<?> i:interfaces){
			System.out.print(i.getName()+", ");
		}

		System.out.println("\n\n"+"运行结果为：");
		userService.test();
	}
}
/* Output:
true
userService的Class类是：class com.sun.proxy.$Proxy0
userService中的属性有：m1, m3, m2, m0,
userService中的方法有：equals, toString, hashCode, test,
userService的父类是：class java.lang.reflect.Proxy
userService实现的接口是：com.gqzdev.aop.proxy.jdk.UserInterface,

运行结果为：
before...
test...
after...
*///~
/**
 * PS：这个结果的信息非常重要，至少对我来说。因为我在动态代理犯晕的根源就在于将上面的 userService.test()理解错了，
 * 至少是被表面所迷惑，没有发现这个 userService 和 Proxy 之间的联系，一度纠结于最后调用的这个 test() 是怎么和
 * invoke()联系上的，而 invoke() 又是怎么知道 test() 存在的。其实上面的 true 和 class $Proxy0 就能解决很多
 * 的疑问，再加上下面将要说的 $Proxy0 的源码，完全可以解决动态代理的疑惑了。
 * 从以上代码和结果可以看出，我们并没有显示的调用 invoke() 方法，但是这个方法确实执行了。
 */